package org.geekbang.projects.config;

import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.spi.ConfigBuilder;
import org.eclipse.microprofile.config.spi.ConfigSource;
import org.eclipse.microprofile.config.spi.Converter;
import org.geekbang.projects.config.converter.Converters;
import org.geekbang.projects.config.converter.MatchableConverter;
import org.geekbang.projects.config.source.*;

import java.util.Iterator;
import java.util.ServiceLoader;

/**
*   默认Builder实现
* @author : KangNing Hu
*/
public class DefaultConfigBuilder implements ConfigBuilder {

	private ConfigSources configSources = new ConfigSources();

	private Converters converters = new Converters();


	private static ConfigurationComponentLoader configurationComponentLoader;

	static {
		//初始化加载器
		ServiceLoader<ConfigurationComponentLoader> serviceLoader = ServiceLoader.load(ConfigurationComponentLoader.class );
		Iterator<ConfigurationComponentLoader> iterator = serviceLoader.iterator();
		configurationComponentLoader = iterator.hasNext() ? iterator.next() : null;
	}


	@Override
	public ConfigBuilder addDefaultSources() {
		configSources.add(EnvironmentConfigSource.INSTANCE);
		configSources.add(FilePropertiesConfigSource.INSTANCE);
		configSources.add(SystemConfigSource.INSTANCE);
		return this;
	}

	@Override
	public ConfigBuilder addDiscoveredSources() {
		if (configurationComponentLoader == null){
			return this;
		}
		configSources.addAll(configurationComponentLoader.loaderConfigSources());
		return this;
	}

	@Override
	public ConfigBuilder addDiscoveredConverters() {
		if (configurationComponentLoader == null){
			return this;
		}
		converters.addAll(configurationComponentLoader.loaderConverters());
		return this;
	}

	@Override
	public ConfigBuilder forClassLoader(ClassLoader loader) {
		return this;
	}

	@Override
	public ConfigBuilder withSources(ConfigSource... sources) {
		this.configSources.add(sources);
		return this;
	}

	@Override
	public ConfigBuilder withConverters(Converter<?>... converters) {
		this.converters.add(converters);
		return this;
	}

	@Override
	public <T> ConfigBuilder withConverter(Class<T> type, int priority, Converter<T> converter) {
		this.converters.add(new MatchableConverter() {
			@Override
			public boolean matching(Class t) {
				return type.isAssignableFrom(t);
			}

			@Override
			public Object convert(String value) throws IllegalArgumentException, NullPointerException {
				return converter.convert(value);
			}
		});
		return this;
	}



	@Override
	public Config build() {
		return new CommonConfig(this.configSources , this.converters);
	}
}
